<template>
	<view class="e-checkbox" :style="[checkboxStyle]" @tap.stop="wrapperClickHandler"
		:class="[ns.bm('label', checkboxGroupContext.props.iconPlacement), checkboxGroupContext.props.borderBottom && checkboxGroupContext.props.placement === 'column' && 'e-border-bottom']">
		<view class="e-checkbox__icon" @tap.stop="iconClickHandler">
			<slot name="icon" :isActive="isActive">
				<view class="e-checkbox__icon-wrap" :class="iconClasses" :style="[iconWrapStyle]">
					<e-icon class="e-checkbox__icon-wrap__icon" name="checkbox-mark" :size="elIconSize"
						:color="elIconColor" />
				</view>
			</slot>
		</view>
		<text @tap.stop="labelClickHandler" :style="{
				color: elDisabled ? elInactiveColor : elLabelColor,
				fontSize: elLabelSize,
				lineHeight: elLabelSize
			}">
			{{ props.label }}
		</text>
	</view>
</template>

<script lang="ts">
	import {
		defineComponent
	} from 'vue'
	import mpMixin from '../../libs/mixin/mpMixin'
	/**
	 * checkbox  复选框
	 * @description 复选框组件一般用于需要多个选择的场景，该组件功能完整，使用方便
	 * @tutorial https://uviewui.com/components/checkbox.html
	 * @property {String | Number | Boolean}	name			checkbox组件的标示符
	 * @property {String}						shape			形状，square为方形，circle为圆型
	 * @property {String | Number}				size			整体的大小
	 * @property {Boolean}						checked			是否默认选中
	 * @property {String | Boolean}				disabled		是否禁用
	 * @property {String}						activeColor		选中状态下的颜色，如设置此值，将会覆盖parent的activeColor值
	 * @property {String}						inactiveColor	未选中的颜色
	 * @property {String | Number}				iconSize		图标的大小，单位px
	 * @property {String}						iconColor		图标颜色
	 * @property {String | Number}				label			label提示文字，因为nvue下，直接slot进来的文字，由于特殊的结构，无法修改样式
	 * @property {String}						labelColor 		label的颜色
	 * @property {String | Number}				labelSize		label的字体大小，px单位
	 * @property {String | Boolean}				labelDisabled	是否禁止点击提示语选中复选框
	 * @property {Object}						customStyle		定义需要用到的外部样式
	 *
	 * @event {Function}	change	任一个checkbox状态发生变化时触发，回调为一个对象
	 * @example <e-checkbox v-model="checked" :disabled="false">天涯</e-checkbox>
	 */
	export default defineComponent({
		name: 'e-checkbox',
		mixins: [mpMixin]
	})
</script>

<script lang="ts" setup>
	import {
		ref,
		reactive,
		computed,
		watch,
		toRefs,
		provide,
		inject,
		onMounted,
		onBeforeUnmount
	} from 'vue'
	import {
		checkboxProps,
		checkboxEmits
	} from './props';
	import {
		checkboxGroupContextKey,
		checkboxContextKey,
		type CheckboxContext
	} from '../../libs/tokens'
	import {
		useNamespace,
		useDisabled,
		useDefaultProps
	} from '../../libs/hooks'
	import {
		deepMerge,
		isArray,
		empty
	} from '../../libs/utils'
	import {
		throwError,
		addUnit,
		addStyle,
		type propagationEvent
	} from '../../libs/utils/_utils'
	import type {
		StyleProperties
	} from '../../libs/tokens'
	import componentsProps from "../../libs/config/componentsProps";
	import type {
		CheckboxProps
	} from "../../libs/config/propsType";
	import preventView from '../prevent-view/index.vue'

	const {
		checkbox: checkboxDefaultProps
	} = toRefs(componentsProps);

	const _props = defineProps(checkboxProps)
	const props = useDefaultProps<CheckboxProps>(_props, checkboxDefaultProps);
	const emit = defineEmits(checkboxEmits)

	const ns = useNamespace('checkbox')
	const checkboxGroupContext = inject(checkboxGroupContextKey)
	if (!checkboxGroupContext) throwError('ECheckbox', 'e-checkbox需要结合e-checkbox-group组件使用')

	const isChecked = ref<boolean | undefined>(false)


	// 是否禁用，如果父组件禁用的话，将会忽略子组件的配置
	const checkboxGroupDisabled = computed(() => checkboxGroupContext.props?.disabled)
	const elDisabled = useDisabled(checkboxGroupDisabled)

	// 是否禁用label点击
	const elLabelDisabled = computed(() => {
		
		return empty(props.value.labelDisabled) ? empty(checkboxGroupContext.props.labelDisabled) ? false :
			checkboxGroupContext.props.labelDisabled :
			props.value.labelDisabled;
	})
	// 组件尺寸，对应size的值，默认值为21px
	const elSize = computed(() => {
		return props.value.size ? props.value.size : (checkboxGroupContext.props.size ? checkboxGroupContext.props.size : 21);
	})
	// 组件的勾选图标的尺寸，默认12px
	const elIconSize = computed(() => {
		return props.value.iconSize ? props.value.iconSize : (checkboxGroupContext.props.iconSize ? checkboxGroupContext
			.props.iconSize : 12);
	})
	// 组件选中激活时的颜色
	const elActiveColor = computed(() => {
		return props.value.activeColor ? props.value.activeColor : (checkboxGroupContext.props.activeColor ?
			checkboxGroupContext.props.activeColor : '#2979ff');
	})
	// 组件选未中激活时的颜色
	const elInactiveColor = computed(() => {
		return props.value.inactiveColor ? props.value.inactiveColor : (checkboxGroupContext.props.inactiveColor ?
			checkboxGroupContext.props.inactiveColor :
			'#c8c9cc')
	})
	// label的颜色
	const elLabelColor = computed(() => {
		return props.value.labelColor ? props.value.labelColor : (checkboxGroupContext.props.labelColor ?
			checkboxGroupContext.props.labelColor : '#606266')
	})
	// 组件的形状
	const elShape = computed(() => {
		return props.value.shape ? props.value.shape : (checkboxGroupContext.props.shape ? checkboxGroupContext.props.shape :
			'circle');
	})
	// label大小
	const elLabelSize = computed(() => {
		return addUnit(props.value.labelSize ? props.value.labelSize : (checkboxGroupContext.props.labelSize ?
			checkboxGroupContext.props.labelSize :
			'15'))
	})
	const elIconColor = computed(() => {
		const iconColor = props.value.iconColor ? props.value.iconColor : (checkboxGroupContext.props.iconColor ?
			checkboxGroupContext.props.iconColor :
			'#ffffff');
		// 图标的颜色
		if (elDisabled.value) {
			// disabled状态下，已勾选的checkbox图标改为elInactiveColor
			return isChecked.value ? elInactiveColor.value : 'transparent'
		} else {
			return isChecked.value ? iconColor : 'transparent'
		}
	})
	const iconClasses = computed(() => {
		let classes : string | string[] = []
		// 组件的形状
		classes.push('e-checkbox__icon-wrap--' + elShape.value)
		if (elDisabled.value) {
			classes.push('e-checkbox__icon-wrap--disabled')
		}
		if (isChecked.value && elDisabled.value) {
			classes.push('e-checkbox__icon-wrap--disabled--checked')
		}
		// 支付宝，头条小程序无法动态绑定一个数组类名，否则解析出来的结果会带有","，而导致失效
		// #ifdef MP-ALIPAY || MP-TOUTIAO
		classes = classes.join(' ')
		// #endif
		return classes
	})
	const isActive = computed(() => isChecked.value && !elDisabled.value)

	const iconWrapStyle = computed(() => {
		// checkbox的整体样式
		const style : StyleProperties = {}
		style.backgroundColor = isActive.value ? elActiveColor.value : '#ffffff'
		style.borderColor = isActive.value ? elActiveColor.value : elInactiveColor.value
		style.width = addUnit(elSize.value)
		style.height = addUnit(elSize.value)
		// 如果是图标在右边的话，移除它的右边距
		if (checkboxGroupContext.props.iconPlacement === 'right') {
			style.marginRight = 0
		}
		return style
	})
	const checkboxStyle = computed(() => {
		const style : StyleProperties = {}
		if (checkboxGroupContext.props.borderBottom && checkboxGroupContext.props.placement === 'row') {
			throwError('ECheckbox', '检测到您将borderBottom设置为true，需要同时将e-checkbox-group的placement设置为column才有效')
		}
		// 当父组件设置了显示下边框并且排列形式为纵向时，给内容和边框之间加上一定间隔
		if (checkboxGroupContext.props.borderBottom && checkboxGroupContext.props.placement === 'column') {
			style.paddingBottom = '8px'
		}
		return deepMerge(style, addStyle(_props.customStyle as Record<string, any>) as Record<string, any>)
	})



	const init = () => {
		// 支付宝小程序不支持provide/inject，所以使用这个方法获取整个父组件，在created定义，避免循环引用
		// updateParentData()
		// 设置初始化时，是否默认选中的状态，父组件e-checkbox-group的value可能是array，所以额外判断
		if (props.value.checked) {
			isChecked.value = true
		} else if (isArray(checkboxGroupContext.props.modelValue)) {
			// 查找数组是是否存在this.name元素值
			isChecked.value = checkboxGroupContext.props.modelValue.some(item => {
				return item === props.value.name
			})
		}
	}
	// 横向两端排列时，点击组件即可触发选中事件
	const wrapperClickHandler = (e : propagationEvent) => {
		checkboxGroupContext.props.iconPlacement === 'right' && iconClickHandler(e)
	}
	// 点击图标
	const iconClickHandler = (e : propagationEvent) => {
		// 如果整体被禁用，不允许被点击
		if (!elDisabled.value) {
			setCheckboxCheckedStatus()
		}
	}
	// 点击label
	const labelClickHandler = (e : propagationEvent) => {
		// 如果按钮整体被禁用或者label被禁用，则不允许点击文字修改状态
		if (!elLabelDisabled.value && !elDisabled.value) {
			setCheckboxCheckedStatus()
		}
	}
	const emitEvent = () => {
		emit('change', !!isChecked.value)
	}



	// 改变组件选中状态
	// 这里的改变的依据是，更改本组件的checked值为true，同时通过父组件遍历所有e-checkbox实例
	// 将本组件外的其他e-checkbox的checked都设置为false(都被取消选中状态)，因而只剩下一个为选中状态
	const setCheckboxCheckedStatus = () => {
		// 将本组件标记为与原来相反的状态
		// console.log(isChecked.value)
		isChecked.value = !isChecked.value
		// console.log(isChecked.value)
		emitEvent()
		typeof checkboxGroupContext.unCheckedOther === 'function' && checkboxGroupContext.unCheckedOther()
	}
	watch(() => props.value.checked, (v) => {
		isChecked.value = v
	})

	const context : CheckboxContext = reactive({
		props,
		isChecked,
		init,
	})

	onMounted(() => {
		init()
		if (checkboxGroupContext) {
			checkboxGroupContext.addField(context)
		}
	})
	onBeforeUnmount(() => {
		checkboxGroupContext.removeField(context)
	})

	provide(checkboxContextKey, context)
</script>

<style lang="scss" scoped>
	@import '../../libs/theme/checkbox.scss';
</style>